#include <math.h>
#include <stdio.h>
#define U_INT16 unsigned short

/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*        MASS FLOW SENSOR  ADC-Flow, Flow-ADC                   */
/*                                                               */
/*        conversion table generator.                            */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                          ( beta * flow )      */
/*   Sensor    =    gamma + alpha * (  1 - e               )     */
/*   Voltage                                                     */
/*                                                               */
/*     gamma = sensor voltage with flow = 0                      */
/*     alpha + gamma = maximum sensor voltage (infinite flow)    */ 
/*     beta  = shape of curve,  decay rate                       */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */
/*                                                               */

#define IU_SCALING 16384

 /**  Helium **/
#define  HE_alpha       2.392727
#define  HE_beta       -0.001048853
#define  HE_gamma       0.998

#define  HE_MAX_FLOW    1100.0            /* mL/Min */


 /**  Hydrogen **/
#define  H2_alpha       2.123326
#define  H2_beta       -0.001472506
#define  H2_gamma       0.98

#define  H2_MAX_FLOW    1100.0            /* mL/min */


 /**  Nitrogen **/
#define  N2_alpha       2.845770
#define  N2_beta       -0.004616411
#define  N2_gamma       1.003

#define  N2_MAX_FLOW    400.0             /* mL/min */



float sensor_to_adc (float sensor )
{
    return (sensor*6/4);
}





float adc_to_sensor ( float adc_in )
{
    return (adc_in*4/6);
}





float        adc_to_digital ( float adc_in )
{

    float adc_out;

    adc_out = adc_in -3;

    /* hard clip limits, just like hardware */
    if (adc_out < -3 ) adc_in = -3;
    if (adc_out > +3 ) adc_in = +3;

    return adc_out*10922;
}






float digital_to_adc ( float        digital )
{
    float adc;

    adc = digital/10922;

    /* hard clip limits, just like hardware */
    if (adc < -3) adc = -3;
    if (adc > +3) adc = +3;

    return adc+3;
}


float   sensor_to_flow ( float sensor,
                         float alpha,
                         float beta,
                         float gamma )

{

      float flow;
      
      /* check for sensor values larger than possible */
      if ((gamma-sensor)/alpha < -1) sensor = alpha + gamma - 1e-6;

      flow = log((gamma - sensor)/alpha+1)/beta ;

      flow = flow/(273.15/298.15); /* SCCM -> mL/Min@NTP */

      /* flows can never be negative */
      if (flow < 0) flow = 0;

      return flow;

}

   
float  flow_to_sensor ( float flow,
                        float alpha,
                        float beta,
                        float gamma )

{

    float sensor;
    float max_flow;
   
    flow = flow*(273.15/298.15); /* mL/Min@NTP -> SCCM */

    sensor = gamma + alpha*(1-exp(beta*flow));

    return sensor;

}


float        flow_to_digital ( float flow,
                               float alpha,
                               float beta,
                               float gamma )
{

     return adc_to_digital( sensor_to_adc( flow_to_sensor ( flow, alpha, beta, gamma )));

}









float        digital_to_flow ( float digital,
                               float alpha,
                               float beta,
                               float gamma )
{

     return sensor_to_flow( adc_to_sensor( digital_to_adc ( digital )), alpha, beta, gamma );

}
   


      

void print_digital_to_flows ( char *gas,
                            float max,
                            float alpha,
                            float beta,
                            float gamma )
{

    short i;
    short digital;
    float flow;

    
    printf ( "\f\nunsigned short %s_adc_to_flow[] = {           ", gas );
   
    for (i= -128 ; i<127 ; i++) 
    {
        digital =  i*256;
        flow    = digital_to_flow(digital ,alpha,beta,gamma );

        /*if ( flow*1.1 > max ) break;*/

        if (((i-4)%6)==0)
           printf ( "\n/*%5hx */  %8lx,", digital, (unsigned long)(flow*IU_SCALING) );
        else
	   printf ( " %8lx,",(unsigned long)(flow*IU_SCALING) );
    }

    digital = i*256;
    flow    = digital_to_flow(digital ,alpha,beta,gamma );

    printf ( " %8lx };\n",(unsigned long)(flow*IU_SCALING) );


}


void print_flows_to_digital( char *gas,
                            float max,
                            float alpha,
                            float beta,
                            float gamma )
{

    float step_rate;
    short i;
    float flow;
    short digital;

    if      ( max <= 256 ) step_rate = 1;
    else if ( max <= 512 ) step_rate = 2;
    else if ( max <= 1024) step_rate = 4;
    else if ( max <= 2048) step_rate = 8;
    else if ( max <= 4096) step_rate = 16;

    printf ( "\f\nunsigned short %s_flow_to_adc[] = {", gas );

    for (i= 0 ; i<255 ; i++ )
    {
        flow = i*step_rate;
   
        digital = (short)flow_to_digital(flow ,alpha,beta,gamma );

        if ((i%8)==0)
	   printf ( "\n/*%7.2f */  %6hx,", flow, digital );
        else
	   printf ( " %6hx,", digital );
    }

    flow = i*step_rate;
    digital = (int)flow_to_digital(flow ,alpha,beta,gamma );
    printf ( " %6hx };\n", digital );


}


void print_flow_per_bit ( char *gas,
                          float alpha,
                          float beta,
                          float gamma )
{
     short zero_flow_digital;

     zero_flow_digital = flow_to_digital( 0.0, alpha, beta, gamma );

     printf ( "\n\nconst unsigned long %s_flow_per_bit = 0x%lx;\n\n", gas,
                  (unsigned long)(digital_to_flow( zero_flow_digital +1, alpha, beta, gamma )*IU_SCALING) );

}

void print_tblu_index_mask ( char *gas, float max )
{

   unsigned long mask;
   short shift_value;

   if      ( max <= 256 ) {  mask = 0x007fff80 ; shift_value = 7; }
   else if ( max <= 512 ) {  mask = 0x00ffff00 ; shift_value = 8; }
   else if ( max <= 1024) {  mask = 0x01fffe00 ; shift_value = 9; }
   else if ( max <= 2048) {  mask = 0x03fffc00 ; shift_value =10; }
   else if ( max <= 4096) {  mask = 0x07fff800 ; shift_value =11; }

   
   printf ( "\nconst unsigned long  %s_tblu_extract_mask = 0x%x;\n\n", gas, mask );
   printf ( "\nconst unsigned short %s_tblu_shift_value  = %d;\n\n", gas, shift_value );

}

void do_nitrogen()
{

   print_digital_to_flows ( "nitrogen",
                          flow_to_digital( N2_MAX_FLOW , N2_alpha, N2_beta, N2_gamma ),
                          N2_alpha,
                          N2_beta,
                          N2_gamma );

   print_flows_to_digital ( "nitrogen",
                          N2_MAX_FLOW,
                          N2_alpha,
                          N2_beta,
                          N2_gamma );

   print_flow_per_bit     ( "nitrogen",
                          N2_alpha,
                          N2_beta,
                          N2_gamma );

   print_tblu_index_mask  ( "nitrogen", N2_MAX_FLOW );

}


void do_hydrogen()
{

   print_digital_to_flows ( "hydrogen",
                          flow_to_digital( H2_MAX_FLOW , H2_alpha, H2_beta, H2_gamma ),
                          H2_alpha,
                          H2_beta,
                          H2_gamma );

   print_flows_to_digital ( "hydrogen",
                          H2_MAX_FLOW,
                          H2_alpha,
                          H2_beta,
                          H2_gamma );

   print_flow_per_bit     ( "hydrogen",
                          H2_alpha,
                          H2_beta,
                          H2_gamma );

   print_tblu_index_mask  ( "hydrogen", H2_MAX_FLOW );

}


void do_helium()
{

   print_digital_to_flows ( "helium",
                          flow_to_digital( HE_MAX_FLOW , HE_alpha, HE_beta, HE_gamma ),
                          HE_alpha,
                          HE_beta,
                          HE_gamma );

   print_flows_to_digital ( "helium",
                          HE_MAX_FLOW,
                          HE_alpha,
                          HE_beta,
                          HE_gamma );

   print_flow_per_bit     ( "helium",
                          HE_alpha,
                          HE_beta,
                          HE_gamma );

   print_tblu_index_mask  ( "helium", HE_MAX_FLOW );

}


int main()
{

   do_helium();

   do_hydrogen();

   do_nitrogen();
  

return 0;
}
